package com.jeehentor.generate.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jeehentor.common.api.SystemCommonAPI;
import com.jeehentor.common.exception.HentorException;
import com.jeehentor.common.vo.OptionsVO;
import com.jeehentor.common.vo.Result;
import com.jeehentor.generate.dto.GenModelDTO;
import com.jeehentor.generate.dto.GenModelQueryDTO;
import com.jeehentor.generate.dto.GenerateCodeDTO;
import com.jeehentor.generate.dto.GenerateSqlDTO;
import com.jeehentor.generate.entity.SysGenModel;
import com.jeehentor.generate.entity.SysGenModelField;
import com.jeehentor.generate.service.ISysGenModelFieldService;
import com.jeehentor.generate.service.ISysGenModelService;
import com.jeehentor.generate.vo.SysGenModelVO;
import com.jeehentor.utils.PageUtil;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.core.io.InputStreamResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

/**
 * @Description : 代码生成
 * @Author : wzd
 * @Date : 2024/5/8 17:15
 * @Version : 1.0
 **/
@RestController
@RequestMapping("/generate")
@Tag(name = "代码生成")
@RequiredArgsConstructor
public class GenerateCodeController {

    private final ISysGenModelService sysGenModelService;
    private final ISysGenModelFieldService sysGenModelFieldService;
    private final SystemCommonAPI systemCommonAPI;

    @PostMapping("/saveModel")
    @Operation(summary = "保存模型")
    public Result<String> saveModel(@RequestBody GenModelDTO dto) {
        sysGenModelService.saveModel(dto);
        return Result.ok("保存成功");
    }

    @PostMapping("/updateModel")
    @Operation(summary = "修改模型")
    public Result<String> updateModel(@RequestBody GenModelDTO dto) {
        sysGenModelService.updateModel(dto);
        return Result.ok("修改成功");
    }

    @PostMapping("/delModel")
    @Operation(summary = "删除模型")
    public Result<String> delModel(@RequestBody GenModelDTO dto) {
        sysGenModelService.delModel(dto);
        return Result.ok("删除成功");
    }
    @PostMapping("/selectModelById")
    @Operation(summary = "查询模型字段")
    public Result<GenModelDTO> selectModelById(@RequestBody GenModelDTO dto) {
        GenModelDTO genModelDTO = sysGenModelService.selectModelById(dto);
        return Result.ok(genModelDTO);
    }

    @PostMapping("/selectModelByTableName")
    @Operation(summary = "查询模型字段")
    public Result<GenModelDTO> selectModelByTableName(@RequestBody GenModelDTO dto) {
        GenModelDTO genModelDTO = new GenModelDTO();
        LambdaQueryWrapper<SysGenModel> sysGenModelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysGenModelLambdaQueryWrapper.eq(SysGenModel::getTableName, dto.getTableName());
        SysGenModel byId = sysGenModelService.getOne(sysGenModelLambdaQueryWrapper);
        BeanUtils.copyProperties(byId, genModelDTO);
        LambdaQueryWrapper<SysGenModelField> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysGenModelField::getModelId, byId.getId());
        queryWrapper.orderByAsc(SysGenModelField::getSortOrder);
        List<SysGenModelField> list = sysGenModelFieldService.list(queryWrapper);
        genModelDTO.setFieldList(list);
        return Result.ok(genModelDTO);
    }

    @PostMapping("/checkFieldExist")
    @Operation(summary = "检查字段是否存在")
    public Result<SysGenModelField> checkFieldExist(@RequestBody SysGenModelField sysGenModelField) {
        LambdaQueryWrapper<SysGenModelField> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysGenModelField::getModelId, sysGenModelField.getModelId());
        queryWrapper.eq(SysGenModelField::getFieldName, sysGenModelField.getFieldName());
        return Result.ok(sysGenModelFieldService.getOne(queryWrapper));
    }

    @PostMapping("/updateFieldById")
    @Operation(summary = "更新字段配置")
    public Result<String> updateFieldById(@RequestBody SysGenModelField sysGenModelField) {
        sysGenModelFieldService.updateById(sysGenModelField);
        return Result.ok("修改成功");
    }

    @PostMapping("/selectFieldOptions")
    @Operation(summary = "查询模型字段下拉")
    public Result<List<OptionsVO>> selectFieldOptions(@RequestBody GenModelDTO dto) {
        LambdaQueryWrapper<SysGenModelField> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SysGenModelField::getModelId, dto.getId());
        queryWrapper.orderByAsc(SysGenModelField::getSortOrder);
        List<SysGenModelField> list = sysGenModelFieldService.list(queryWrapper);
        ArrayList<OptionsVO> optionsVOS = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(list)){
            list.forEach(x->{
                OptionsVO optionsVO = new OptionsVO();
                optionsVO.setLabel(x.getRemarks());
                optionsVO.setValue(x.getFieldName());
                optionsVOS.add(optionsVO);
            });
        }
        return Result.ok(optionsVOS);
    }

    @PostMapping("/modelPageList")
    @Operation(summary = "模型分页查询")
    public Result<Page<SysGenModelVO>> modelPageList(@RequestBody GenModelQueryDTO dto) {
        LambdaQueryWrapper<SysGenModel> sysGenModelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysGenModelLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getTableName()), SysGenModel::getTableName, dto.getTableName());
        sysGenModelLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getTableComment()), SysGenModel::getTableComment, dto.getTableComment());
        Page<SysGenModel> page = sysGenModelService.page(dto.getPage(), sysGenModelLambdaQueryWrapper);
        Page<SysGenModelVO> sysGenModelVOPage = PageUtil.conversionVoPage(page, SysGenModelVO.class);
        if(CollectionUtil.isNotEmpty(sysGenModelVOPage.getRecords())){
            sysGenModelVOPage.getRecords().forEach(x->{
                x.setCreateByLabel(systemCommonAPI.getUserById(x.getCreateBy()).getUsername());
                x.setUpdateByLabel(systemCommonAPI.getUserById(x.getUpdateBy()).getUsername());
            });
        }
        return Result.OK(sysGenModelVOPage);
    }
    @PostMapping("/modelList")
    @Operation(summary = "模型无分页查询")
    public Result<List<SysGenModel>> modelList(@RequestBody GenModelQueryDTO dto) {
        LambdaQueryWrapper<SysGenModel> sysGenModelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysGenModelLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getTableName()), SysGenModel::getTableName, dto.getTableName());
        sysGenModelLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getTableName()), SysGenModel::getTableComment, dto.getTableName());
        List<SysGenModel> list = sysGenModelService.list(sysGenModelLambdaQueryWrapper);
        return Result.OK(list);
    }

    @PostMapping("/getModelOptions")
    @Operation(summary = "模型下拉查询")
    public Result<List<OptionsVO>> getModelOptions(@RequestBody GenModelQueryDTO dto) {
        LambdaQueryWrapper<SysGenModel> sysGenModelLambdaQueryWrapper = new LambdaQueryWrapper<>();
        sysGenModelLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getTableName()), SysGenModel::getTableName, dto.getTableName());
        sysGenModelLambdaQueryWrapper.like(StringUtils.isNotBlank(dto.getTableName()), SysGenModel::getTableComment, dto.getTableName());
        List<SysGenModel> list = sysGenModelService.list(sysGenModelLambdaQueryWrapper);
        ArrayList<OptionsVO> optionsVOS = new ArrayList<>();
        if(CollectionUtil.isNotEmpty(list)){
            list.forEach(x->{
                OptionsVO optionsVO = new OptionsVO();
                optionsVO.setLabel(x.getTableComment());
                optionsVO.setValue(x.getId());
                optionsVOS.add(optionsVO);
            });
        }
        return Result.OK(optionsVOS);
    }

    @PostMapping("/syncDataBase")
    @Operation(summary = "同步数据库")
    public Result<String> syncDataBase(@RequestBody GenModelDTO dto) throws Exception {
        sysGenModelService.syncDataBase(dto);
        return Result.ok("同步成功");
    }

    @PostMapping("/codeFileGenerator")
    @Operation(summary = "生成代码并下载文件")
    public ResponseEntity<InputStreamResource> codeFileGenerator(@RequestBody GenerateCodeDTO dto) throws Exception {
        //模块
        if(StringUtils.isBlank(dto.getModuleName())){
            dto.setModuleName("temp");
        }
        //路径
        if(StringUtils.isBlank(dto.getPackagePath())){
            dto.setPackagePath("com.jeehentor.test");
        }

        List<String> filePaths = sysGenModelService.codeFileGenerator(dto);
        if(CollectionUtil.isEmpty(filePaths)){
            throw new HentorException("代码未生成!");
        }
        List<Path> files = new ArrayList<>();
        filePaths.forEach(x->{
            files.add(Paths.get(x));
        });
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        try (ZipArchiveOutputStream zipOutputStream = new ZipArchiveOutputStream(byteArrayOutputStream)) {
            createZipWithFiles(files, zipOutputStream);
        }

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        InputStreamResource resource = new InputStreamResource(byteArrayInputStream);

        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=download.zip");

        return ResponseEntity.ok()
                .headers(headers)
                .contentLength(byteArrayInputStream.available())
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(resource);
    }

    @PostMapping("/importSql")
    @Operation(summary = "导入sql")
    public Result<String> importSql(@RequestBody GenerateSqlDTO dto) {
        sysGenModelService.importSql(dto);
        return Result.ok("保存成功");
    }


    private void createZipWithFiles(List<Path> files, ZipArchiveOutputStream zipOutputStream) throws Exception {
        for (Path file : files) {
            addFileToZip(file, zipOutputStream);
        }
        zipOutputStream.finish();
    }

    private void addFileToZip(Path file, ZipArchiveOutputStream zipOutputStream) throws Exception {
        try (InputStream inputStream = new FileInputStream(file.toFile())) {
            String regx = "";
            String targetSubstring = "/temp";
            int indexOfTargetSubstring = file.toString().indexOf(targetSubstring);
            if (indexOfTargetSubstring != -1) {
                regx = file.toString().substring(0, indexOfTargetSubstring);
            }
            String filePath = file.toString().replaceFirst(regx, "");
            ZipArchiveEntry entry = new ZipArchiveEntry(filePath);
            zipOutputStream.putArchiveEntry(entry);
            IOUtils.copy(inputStream, zipOutputStream);
            zipOutputStream.closeArchiveEntry();
        }
    }
}
